// 封装axios请求
import axios from 'axios'
import { MessageBox, Message } from 'element-ui' // 引入element-ui提供的弹窗
import store from '@/store' // 引入仓库
import { getToken } from '@/utils/auth' // 引入添加cookie值

// axios.create：创建一个自定义的axios实例
// 该service实例等同于之前的axios,只是这里添加了一些特殊配置
const service = axios.create({
  // baseURL：基地址
  // 请求的地址会与基地址自动拼接 = baseURL + url
  baseURL: process.env.VUE_APP_BASE_API,
  // 设置超时事件，ms
  timeout: 5000
})

// 设置请求拦截器
// views逻辑页面中 ->调用api里的接口方法 -> request.js中的service(axios方法) -> 再执行请求拦截器
service.interceptors.request.use(
  // 参数1：箭头函数体 -> 发起请求之前会走这里(必须return 请求配置对象，return到axios的use内)
  config => { // config里包含axios内置配置还有api接口方法里你写的url/data/params/methods等参数
    // 判断vuex中是否有token(是否登陆状态)
    if (store.getters.token) {
      // 把token值，拼接在请求头加入key叫 X-Token ，值为token值
      config.headers['X-Token'] = getToken()
    }
    return config
  },
  // 参数2：箭头函数体 -> 在发起请求前，axios内有报错，会直接进入error函数体内
  error => {
    // 打印错误对象，返回promise的reject状态
    console.log(error) // for debug
    // Promise.reject(error)等价于promise((resolve,reject)=>{reject(error)})
    return Promise.reject(error)
  }
)

// 设置响应拦截器
service.interceptors.response.use(
  // 参数1：箭头函数体 -> (成功)只有在响应状态码为2xx,3xx时，进入参数1
  response => {
    // response：axios封装的一个响应对象
    // data选项里才是后台返回的真正数据
    const res = response.data

    // 20000，是与后台提前设定的，(在http状态码的基础上，来判断是否真正成功了)，而是前后台商议通过返回的值中的code码来判断是否成功
    // 重点：
    // http响应过程是成功的，但是逻辑有问题，就会出现状态码是200，但是返回结果不是我们想要的
    // 例如：登陆状态，当前端将账号密码都发送给后台了，后台也作出了正确的回应，但是账号或者密码是错误的，这是就会出现状态码正确，但是返回的code码不对的情况
    if (res.code !== 20000) { // 请求错误
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })

      // 错误的返回code值
      // 50008: 非法令牌; 50012: 其他客户登录; 50014: 令牌过期;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // to re-login
        MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
          confirmButtonText: 'Re-Login',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload()
          })
        })
      }
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      // 完全成功
      return res // 返回的是后台的真实数据，不是经过axios封装的响应对象
    }
  },
  // 参数2：箭头函数体 -> (失败)只有在响应状态码为4xx,5xx(或者捕获到了其他错误)时，进入
  error => {
    // 打印错误信息
    console.log('err' + error)
    // 给用户一个弹窗提醒，element-ui
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    })
    // axios()函数原地，那个promise对象接受到了失败的状态
    return Promise.reject(error)
  }
)

export default service
